use std::ops::{Deref};

use lazy_static::lazy_static;
use sqlx::{Pool, ConnectOptions};
use sqlx::Postgres;
use sqlx::postgres::PgPoolOptions;
use std::fs;
use std::sync::{Mutex, MutexGuard};
use crate::common::config::SerialConfig;
use crate::common::constant;
use std::collections::HashMap;
use scheduled_thread_pool::ScheduledThreadPool;
use log::LevelFilter;
use crate::mqtt::enhanced::MqttClient;
use crate::serial::SerialSender;

// DATABASE_RELATION 数据库关系名称
// DB_CONN_POOL 数据库连接池
// MAC_ADDRESS 本机MAC地址
// SERIAL_CONFIG 串口配置
// SERIAL_SENDER 串口对应的发送队列
// SCHEDULED 定时器线程池
// MQTT_MAC 根据MAC生成的MQTT ID与本地TOPIC
// MQTT_CLIENT MQTT的客户端
lazy_static! {
    static ref DATABASE_RELATION : String = envmnt::get_or("DATABASE_RELATION", "postgres");
    static ref DB_CONN_POOL : Pool<Postgres> = init_conn();
    static ref MAC_ADDRESS : String = mac_address::get_mac_address().unwrap().unwrap().to_string();
    static ref SERIAL_CONFIG : SerialConfig = init_serial_config();
    static ref SERIAL_SENDER : Mutex<HashMap<String,SerialSender>> =Mutex::new(HashMap::new());
    static ref SCHEDULED : ScheduledThreadPool = ScheduledThreadPool::new(16);
    static ref MQTT_MAC : String = init_mqtt_mac();
    pub static ref MQTT_CLIENT : Mutex<MqttClient> = init_mqtt_client();
}

/// 初始化数据库链接
/// 通过ENV的配置进行链接
fn init_conn() -> Pool<Postgres>
{
    let mut conn_opt = sqlx::postgres::PgConnectOptions::new()
        .host(&envmnt::get_or("DATABASE_HOST", "127.0.0.1"))
        .port(envmnt::get_u16("DATABASE_PORT", 5432))
        .username(&envmnt::get_or("DATABASE_USERNAME", "postgres"))
        .password(&envmnt::get_or("DATABASE_PASSWORD", ""))
        .database(&envmnt::get_or("DATABASE_BASE", "postgres"));

    let level =
        if envmnt::is_or("LOG_DEBUG", false)
        { LevelFilter::Debug } else { LevelFilter::Off };
    conn_opt.log_statements(level);

    let stream = PgPoolOptions::new()
        .max_connections(5)
        .connect_with(conn_opt);

    futures::executor::block_on(stream).unwrap()
}

/// 初始化串口配置到全局
fn init_serial_config() -> SerialConfig {
    let path = envmnt::get_or_panic(constant::SERIAL_CONFIG_PATH);
    let json = fs::read_to_string(path).unwrap();
    serde_json::from_str(&json).unwrap()
}

/// 根据MAC地址生成\
/// 例如: 00:50:C2:40:E8:BA -> 00_50_C2_40_E8_BA
fn init_mqtt_mac() -> String {
    mac_address().replace(":", "_")
}

/// 初始化Mqtt的客户端\
fn init_mqtt_client() -> Mutex<MqttClient> {
    let client = MqttClient::new(
        &envmnt::get_or("MQTT_HOST", "127.0.0.1"),
        envmnt::get_u16("MQTT_PORT", 1883),
        mqtt_mac(),
    ).unwrap();
    Mutex::new(client)
}

pub fn db_conn_pool() -> &'static Pool<Postgres>
{ DB_CONN_POOL.deref() }

pub fn mac_address() -> &'static str
{ MAC_ADDRESS.as_str() }

pub fn serial_config() -> &'static SerialConfig
{ SERIAL_CONFIG.deref() }

pub fn serial_sender() -> MutexGuard<'static, HashMap<String, SerialSender>>
{ SERIAL_SENDER.lock().unwrap() }

pub fn serial_sender_clone(port:&str) -> Option<SerialSender> {
    let map = serial_sender();
    let sender = map.get(port)?;
    Some(sender.clone())
}

pub fn scheduled() -> &'static ScheduledThreadPool
{ SCHEDULED.deref() }

pub fn database_relation() -> &'static String
{ DATABASE_RELATION.deref() }

pub fn mqtt_mac() -> &'static String
{ MQTT_MAC.deref() }

pub fn mqtt_client() -> MutexGuard<'static, MqttClient>
{ MQTT_CLIENT.lock().unwrap() }